package com.java.base.exercise.current;

import lombok.SneakyThrows;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.LockSupport;

/**
 * @Author RenPu
 * @Date 2023/3/14 17:51
 * @Version 1.0
 * @Description: 手动模拟实现 FutureTask
 **/
public class RenPuFutureTask<T> implements Runnable {

    private Callable<T> callable;

    //结果集
    private T result;

    //mark标志 volatile修饰避免伪共享的问题，同时保证了线程之间的可见性
    private volatile String state="NEW";

    //线程等待队列容器
    private LinkedBlockingQueue<Thread> waiterQueque=new LinkedBlockingQueue<>(2000);


    public RenPuFutureTask(Callable<T> callable) {
        this.callable = callable;
    }


    /**
     * FutureTask结果集获取方法
     * @return
     */
    public T get(){
        //判断标志如果run方法中的call方法，已经执行完毕了则进行直接返回结果集
        if("END".equals(state)){
            return result;
        }
        //如果没有执行完成则进行，一直进行阻塞
        while (!"END".equals(state)){
            //使用LockSupport机制进行线程之间的通信，需要明确挂起的线程为哪一个，
            // 此时需要设计一个容器进行存储线程
            waiterQueque.offer(Thread.currentThread());
            LockSupport.park();
        }
       return result;
    }



    @Override
    public void run() {
        //此时考虑如何保证将，call的方法执行完后，在进行执行get方法，
        // call方法没有执行前，get方法都需要进行阻塞等待
        try {
            result=callable.call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        //方法执行完毕之后需要，更改状态值便于get方法解除阻塞状态
            state="END";
        }

        //判断等待队列获取的线程是否为null值
        Thread thread = waiterQueque.poll();
        while (thread!=null){
            //一直循环进行从，等到队列进行获取并进行唤醒线程，进行执行get方法
            LockSupport.unpark(thread);
            waiterQueque.poll();

            //当容器里存储的不止一个等待线程元素，进行直接获取并进行唤醒
            thread=waiterQueque.poll();
        }


    }










    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = new Callable<String>() {

            @Override
            public String call() throws Exception {
                return "方法开始执行了。。。。。。";
            }
        };

        //FutureTask<String> futureTask = new FutureTask<>(callable);
        RenPuFutureTask<String> futureTask = new RenPuFutureTask<>(callable);
        new Thread(futureTask).start();
        String result = futureTask.get();
        System.out.println("打印结果值："+result);



    }


}
